package felix.rule.module.filter;

import felix.rule.api.*;
import felix.rule.api.util.TNodeUtils;
import felix.rule.data.msg.EngineMsg;
import felix.rule.data.plugin.ComponentType;
import felix.rule.js.script.ScriptEngine;
import felix.rule.js.util.ListeningExecutor;
import lombok.extern.slf4j.Slf4j;

import java.util.Set;

import static felix.rule.js.util.DonAsynchron.withCallback;

@Slf4j
@RuleNode(
        type = ComponentType.FILTER,
        name = "switch", customRelations = true,
        relationTypes = {},
        configClazz = TJsSwitchNodeConfiguration.class,
        nodeDescription = "Route incoming Message to one or multiple output chains",
        nodeDetails = "Node executes configured JS script. Script should return array of next Chain names where Message should be routed. " +
                "If Array is empty - message not routed to next Node. " +
                "Message payload can be accessed via <code>msg</code> property. For example <code>msg.temperature < 10;</code><br/>" +
                "Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
                "Message type can be accessed via <code>msgType</code> property.",
        uiResources = {"static/rulenode/rulenode-core-config.js"},
        configDirective = "tFilterNodeSwitchConfig")
public class TJsSwitchNode implements TNode {

    private TJsSwitchNodeConfiguration config;
    private ScriptEngine jsEngine;

    @Override
    public void init(TContext ctx, TNodeConfiguration configuration) throws TNodeException {
        this.config = TNodeUtils.convert(configuration, TJsSwitchNodeConfiguration.class);
        this.jsEngine = ctx.createJsScriptEngine(config.getJsScript());
    }

    @Override
    public void onMsg(TContext ctx, EngineMsg msg) {
        ListeningExecutor jsExecutor = ctx.getJsExecutor();
        withCallback(jsExecutor.executeAsync(() -> jsEngine.executeToSet(msg)),
                result -> {
                    processSwitch(ctx, msg, result);
                },
                t -> {
                    ctx.tellFailure(msg, t);
                }, ctx.getJsExecutor());
    }

    private void processSwitch(TContext ctx, EngineMsg msg, Set<String> nextRelations) {
        ctx.tellNext(msg, nextRelations);
    }

    @Override
    public void destroy() {
        if (jsEngine != null) {
            jsEngine.destroy();
        }
    }
}
